package com.gui;

import com.gooddies.wiring.Wiring;
import com.gooddies.wiring.annotations.PostWiring;
import com.gooddies.wiring.annotations.Wire;
import com.gooddies.wiring.annotations.WiringComponent;
import com.gui.interfaces.ErrorListContainer;
import com.gui.interfaces.StatusTextManipulator;
import com.peg.dataobjects.ErrorMessage;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import javax.swing.DefaultListModel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;

/**
 *
 * @author sad
 */
@WiringComponent(singleton = true, name = "MainFrame")
public class MainFrame extends javax.swing.JFrame implements StatusTextManipulator, ErrorListContainer {

    private Debugger debugger;
    @Wire
    private ParsingContext parsingContext;

    private final TextLineNumber textLineNumber;

    public MainFrame() {
        initComponents();
        errorList.setModel(new DefaultListModel());
        textLineNumber = new TextLineNumber();
        Wiring.get().addOverride("GrammarLineNumbers", textLineNumber);
    }

    @PostWiring
    private void initTextFields() {
        JTextPane grammarCodeTextField = Wiring.getComponent(GrammarEditor.class);
        JScrollPane tScrollPane = new JScrollPane(grammarCodeTextField);
        textLineNumber.install(grammarCodeTextField);
        tScrollPane.setRowHeaderView(textLineNumber);
        placeForGrammarCode.add(tScrollPane);
        JTextPane grammarDataField = Wiring.getComponent(DataEditor.class);
        tScrollPane = new JScrollPane(grammarDataField);
        TextLineNumber tln = new TextLineNumber();
        tln.install(grammarDataField);
        tScrollPane.setRowHeaderView(tln);
        placeForData.add(tScrollPane);
    }

    @PostWiring
    private void initDebugger() {
        long eventMask = AWTEvent.KEY_EVENT_MASK;

        AWTEventListener listener = new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent e) {
                if (e instanceof KeyEvent) {
                    KeyEvent kevent = (KeyEvent) e;
                    if (kevent.getID() == KeyEvent.KEY_PRESSED && kevent.getKeyCode() == KeyEvent.VK_F8) {
                        debuggerStep();
                    }
                    if (kevent.getID() == KeyEvent.KEY_PRESSED && kevent.getKeyCode() == KeyEvent.VK_F5) {
                        debuggerRun();
                    }

                }

                e.getID();
            }
        };

        Toolkit.getDefaultToolkit().addAWTEventListener(listener, eventMask);
    }

    private void debuggerStep() {
        if (debugger != null) {
            debugger.step();
        } else {
            debugger = Wiring.getComponent(Debugger.class);
            debugger.setStepFlag(true);
            parseText();
            debugger = Wiring.getComponent(Debugger.class);
        }
    }

    private void debuggerRun() {
        if (debugger != null) {
            debugger.run();
        } else {
            debugger = Wiring.getComponent(Debugger.class);
            debugger.setStepFlag(false);
            parseText();
        }
    }

    private void debuggerClose() {
        if (debugger != null) {
            debugger.closeSession();
            debugger = null;
            setStatusText("End debugging");
        }
    }

    private void parseText() {
        try {
            DataEditor editor = Wiring.getComponent(DataEditor.class);
            editor.setForeground(Color.BLACK);
            String str = editor.getDocument().getText(0, editor.getDocument().getLength());
            parseTextInThread(str, editor);
        } catch (BadLocationException ex) {
            throw new RuntimeException(ex);
        }
    }

    private void parseTextInThread(final String text, final DataEditor editor) {
        if (parsingContext.getBaseParser() != null) {
            ParsingThread thread = new ParsingThread(editor, text);
            thread.start();
        }
    }

    public class ParsingThread extends Thread {

        private final JTextPane editor;
        private final String text;

        public ParsingThread(JTextPane editor, String text) {
            this.editor = editor;
            this.text = text;
        }

        @Override
        public void run() {
            final boolean result = parsingContext.getBaseParser().parse(text);
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    if (result == true) {
                        editor.setForeground(Color.BLACK);
                    } else {
                        editor.setForeground(Color.RED);
                    }

                    debuggerClose();
                }
            });
        }
    }

    @Override
    public void setStatusText(String statusText) {
        statusBarLabel.setText(statusText);
    }

    @Override
    public void clearErrors() {
        ((DefaultListModel) errorList.getModel()).clear();
    }

    @Override
    public void addError(ErrorMessage errorMessage) {
        ((DefaultListModel) errorList.getModel()).addElement(errorMessage);
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        statusBarLabel = new javax.swing.JLabel();
        mainVerticalSplit = new javax.swing.JSplitPane();
        mainHorizontalSplitPane = new javax.swing.JSplitPane();
        placeForGrammarCode = new javax.swing.JPanel();
        placeForData = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        errorList = new javax.swing.JList();
        jMenuBar1 = new javax.swing.JMenuBar();
        FileMenu = new javax.swing.JMenu();
        runMenuMain = new javax.swing.JMenu();
        runMenu = new javax.swing.JMenuItem();
        stepMenu = new javax.swing.JMenuItem();
        stopDebugMenu = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("JavaPeg");

        jPanel1.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true));
        jPanel1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jPanel1MouseClicked(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusBarLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusBarLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 25, Short.MAX_VALUE)
        );

        mainVerticalSplit.setDividerLocation(300);
        mainVerticalSplit.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        mainVerticalSplit.setOneTouchExpandable(true);

        mainHorizontalSplitPane.setDividerLocation(300);

        placeForGrammarCode.setLayout(new java.awt.BorderLayout());
        mainHorizontalSplitPane.setLeftComponent(placeForGrammarCode);

        placeForData.setLayout(new java.awt.BorderLayout());
        mainHorizontalSplitPane.setRightComponent(placeForData);

        mainVerticalSplit.setTopComponent(mainHorizontalSplitPane);

        errorList.setForeground(new java.awt.Color(204, 0, 0));
        errorList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jScrollPane1.setViewportView(errorList);

        mainVerticalSplit.setRightComponent(jScrollPane1);

        FileMenu.setText("File");
        jMenuBar1.add(FileMenu);

        runMenuMain.setText("Run");

        runMenu.setText("Run F5");
        runMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                runMenuActionPerformed(evt);
            }
        });
        runMenuMain.add(runMenu);

        stepMenu.setText("Step F8");
        stepMenu.setName(""); // NOI18N
        stepMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stepMenuActionPerformed(evt);
            }
        });
        runMenuMain.add(stepMenu);

        stopDebugMenu.setText("stop Debugging");
        stopDebugMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopDebugMenuActionPerformed(evt);
            }
        });
        runMenuMain.add(stopDebugMenu);

        jMenuBar1.add(runMenuMain);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(mainVerticalSplit, javax.swing.GroupLayout.DEFAULT_SIZE, 721, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(mainVerticalSplit, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jPanel1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPanel1MouseClicked
    }//GEN-LAST:event_jPanel1MouseClicked

    private void runMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runMenuActionPerformed
        debuggerRun();
    }//GEN-LAST:event_runMenuActionPerformed

    private void stepMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stepMenuActionPerformed
        debuggerStep();
    }//GEN-LAST:event_stepMenuActionPerformed

    private void stopDebugMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopDebugMenuActionPerformed
        debuggerClose();
    }//GEN-LAST:event_stopDebugMenuActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu FileMenu;
    private javax.swing.JList errorList;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSplitPane mainHorizontalSplitPane;
    private javax.swing.JSplitPane mainVerticalSplit;
    private javax.swing.JPanel placeForData;
    private javax.swing.JPanel placeForGrammarCode;
    private javax.swing.JMenuItem runMenu;
    private javax.swing.JMenu runMenuMain;
    private javax.swing.JLabel statusBarLabel;
    private javax.swing.JMenuItem stepMenu;
    private javax.swing.JMenuItem stopDebugMenu;
    // End of variables declaration//GEN-END:variables
}
